﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using RuoVea.ExApp;
using RuoVea.ExConfig;
using RuoVea.ExUtil;
using RuoVea.Identity.Utils;

namespace RuoVea.Identity.Server;

public static class AuthorizeExtion
{
    /// <summary>
    /// DI
    /// </summary>
    /// <param name="services"></param>
    /// <param name="clients"></param>
    /// <param name="jWTSetting"></param>
    /// <param name="identityOptions"></param>
    public static void AddIdentityServer(this IServiceCollection services, List<AuthServerInfo> clients, string jWTSetting, string identityOptions)
    {

        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);
        services.Configure<CookiePolicyOptions>(options => { 
            options.MinimumSameSitePolicy = SameSiteMode.Unspecified; 
            options.Secure = CookieSecurePolicy.SameAsRequest; });
        ServerConfig.Clients = clients;
        ServerConfig.JWTSetting = Appsettings.GetConfig<JWTSetting>(jWTSetting); 
        ServerConfig.IdentityOptions = Appsettings.GetConfig<IdentityOptions>(identityOptions);
    }

    #region 扩展思路
    //using Microsoft.AspNetCore.Authentication;
    //using System.Threading.Tasks;
    //public static class AuthenticationExtensions
    //{
    //    public static async Task SignOutAsync(this AuthenticationHttpContextExtensions httpContext, string scheme)
    //    {
    //        // 在这里添加你的自定义逻辑
    //        // 例如，你可以在用户注销前记录一些信息
    //        // 你可以使用 httpContext.Items 来共享信息，或者使用其他方式
    //        // 然后调用 .NET Core 的 SignOutAsync
    //        await httpContext.SignOutAsync(scheme);
    //        // 注销后的额外处理逻辑
    //        // 例如，你可以删除cookie，清理session数据等
    //    }
    //} 

//using Microsoft.AspNetCore.Http;
//using Microsoft.AspNetCore.Http.Authentication;
//using Microsoft.Extensions.Logging;
//public static class HttpContextExtensions
//{
//    public static async Task SignOutAsync(this HttpContext context, string scheme)
//    {
//        var authenticationScheme = scheme ?? Microsoft.AspNetCore.Authentication.DefaultAuthenticationScheme;
//        var authenticationHandler = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>().GetHandlerAsync(context, authenticationScheme).Result;
//        if (authenticationHandler is null)
//        {
//            throw new InvalidOperationException($"No authentication handler is available for the scheme '{authenticationScheme}'.");
//        }
//        var authenticationManager = context.RequestServices.GetRequiredService<IAuthenticationManager>();
//        var logger = context.RequestServices.GetRequiredService<ILogger<HttpContextExtensions>>();
//        try
//        {
//            await authenticationManager.SignOutAsync(authenticationScheme);
//            logger.LogInformation($"User signed out successfully from scheme '{authenticationScheme}'.");
//        }
//        catch (Exception ex)
//        {
//            logger.LogError(ex, $"Error occurred while signing out from scheme '{authenticationScheme}'.");
//            throw;
//        }
//    }
//}
#endregion

/// <summary>
/// 
/// </summary>
/// <param name="app"></param>
/// <returns></returns>
public static WebApplication AddServerEndpoint(this WebApplication app)
    {
       async Task SignOutAsync(HttpContext context)
        {
            await context.SignOutAsync();
            context.Response.Redirect("/");
        }

        app.UseEndpoints(endpoints =>
        {
            endpoints.Map("logout", SignOutAsync);


            endpoints.MapGet("/auth/myauthorize", async context =>
            {
                string clientId = context.Request.Query.SingleOrDefault(x => x.Key == "clientid").Value.ToString();
                string redirectUri = context.Request.Query.SingleOrDefault(x => x.Key == "redirecturi").Value.ToString();
                string responseType = context.Request.Query.SingleOrDefault(x => x.Key == "responsetype").Value.ToString();
                string state = context.Request.Query.SingleOrDefault(x => x.Key == "state").Value.ToString();
                string nonce = context.Request.Query.SingleOrDefault(x => x.Key == "nonce").Value.ToString();
                string returnUrl = context.Request.Query.SingleOrDefault(x => x.Key == "returnurl").Value.ToString();

                if (redirectUri.IsNullOrWhiteSpace())
                {
                    context.Response.Redirect("/");
                    return;
                }

                string callback = redirectUri + $"?id_token=err&state={state}&nonce={nonce}";

                if (clientId.IsNullOrWhiteSpace() || state.IsNullOrWhiteSpace() || redirectUri.IsNullOrWhiteSpace() || responseType.IsNullOrWhiteSpace())
                {
                    context.Response.Redirect(callback);
                    return;
                }

                var authorize = ServerConfig.Clients.Where(x => x.ClientId == clientId).FirstOrDefault();


                if (authorize == null)
                {
                    context.Response.Redirect(callback);
                    return;
                }

                if (authorize.RedirectUris == null || authorize.RedirectUris.Count() == 0 || !authorize.RedirectUris.Any(x => x == redirectUri))
                {
                    context.Response.Redirect(callback);
                    return;
                }

                if (responseType != authorize.ResponseType.ToString())
                {
                    context.Response.Redirect(callback);
                    return;
                }

                if (state.IsNullOrWhiteSpace())
                {
                    context.Response.Redirect(callback);
                    return;
                }

                string enrNonce = ConfigUtil.EnrNonce(clientId, authorize.ClientSecrets, redirectUri, authorize.ResponseType);

                if (nonce.IsNullOrWhiteSpace() || enrNonce != nonce)
                {
                    context.Response.Redirect(callback);
                    return;
                }

                string token = "";
                context.Request.Cookies.TryGetValue("token", out token);
                if (App.User.Identity.IsAuthenticated ||token.NotNullOrWhiteSpace())
                {
                    var currUser = App.User.Claims.Distinct().ToDictionary(o => o.Type, o => o.Value);
                    string id_token = ExIdGen.IdGenerator.IdStr("token");
                    string access_token = JWTHelper.CreateJwtToken(ServerConfig.JWTSetting, currUser);
                    var expiredTime = Appsettings.app("JWTSettings:ExpiredTime");
                    string mreturnUrl = redirectUri + $"?id_token={id_token}&access_token={access_token}&token={ExIdGen.IdGenerator.Id}&state={state}&nonce={nonce}&expires_in={expiredTime}&returnurl={returnUrl}";
                    context.Response.Redirect(mreturnUrl);
                }
                else
                {
                    string mreturnUrl = "/auth/login" + $"?returnurl=/auth/myauthorize?clientid={authorize.ClientId}&redirecturi={redirectUri}&responsetype={responseType}&returnurl={returnUrl}&state={state}&nonce={enrNonce}";
                    context.Response.Redirect(mreturnUrl);
                }
            });
        });
        return app;
    }
}
